﻿using System;
using System.Linq;
using FlowCanvas;
using NodeCanvas.Framework;

namespace Snake.Gameplay
{
    public class GameplayAbilitySpec
    {
        public readonly GameplayAbility Ability;
        public GameplayAbilitiesContainer Container { get; set; }

        public GameplayAbilityComponent Owner => Container.Owner;

        public AbilityStatus Status { get; private set; }

        private FlowScriptController Graph => Owner.GetComponent<FlowScriptController>();

        public GameplayAbilitySpec(GameplayAbility ability)
        {
            Ability = ability;
        }

        public void OnGiven()
        {
            Graph.StartBehaviour(Ability.flowScript, NodeCanvas.Framework.Graph.UpdateMode.Manual);
            Owner.Blackboard.AddVariable<GameplayAbilitySpec>(Ability.abilityTag, this);
            Graph.blackboard.AddVariable("AbilityTag", Ability.abilityTag);
            Graph.blackboard.AddVariable("Spec", this);

            Owner.RegisterEvent(OnGameplayEvent);
        }

        private void OnGameplayEvent(GameplayEvent obj)
        {
            switch (obj)
            {
                case GameplayTriggerTagEvent:
                {
                    break;
                }
                default:
                {
                    Graph.SendEvent("GameplayEvent", obj.Tag, Owner);
                    break;
                }
            }
        }

        private void OnGameplayTriggerTagEvent(GameplayEvent obj)
        {
            switch (obj)
            {
                case GameplayTriggerTagEvent evt:
                {
                    Graph.SendEvent("GameplayTriggerTagEvent", evt.Tag, Owner);
                    break;
                }
            }
        }

        private void TryTrigger()
        {
            if (Ability.abilityTriggers.Count == 0)
            {
                return;
            }

            foreach (var trigger in Ability.abilityTriggers)
            {
                // TODO 触发器
            }
        }

        /// <summary>
        /// 尝试激活能力
        /// </summary>
        public bool TryActivateAbility()
        {
            //激活中不能再次激活
            if (Status == AbilityStatus.Activating)
            {
                return false;
            }

            //检查需要拥有的tag
            if (Ability.sourceRequiredTags.Length > 0 && !Owner.TagContainer.HasAll(Ability.sourceRequiredTags))
            {
                return false;
            }

            //检查不能拥有的tag，比如冷却效果存在时的tag
            if (Ability.sourceBlockedTags.Length > 0 && Owner.TagContainer.HasAny(Ability.sourceBlockedTags))
            {
                return false;
            }

            //检查Cost
            if (Ability.costEffect)
            {
                if (Ability.costEffect.durationPolicy != DurationPolicy.Instant)
                {
                    throw new NotSupportedException("Cost effect must be instant.");
                }

                if (!Ability.costEffect.modifiers.All(modifier => modifier.CanApply(Owner.AttributeSet)))
                {
                    return false;
                }
            }

            //条件检查完毕，激活能力
            ActivateAbility();
            return true;
        }

        /// <summary>
        /// 激活能力，需要应用Cost和Cooldown效果
        /// </summary>
        private void ActivateAbility()
        {
            if (Ability.costEffect)
            {
                var spec = GameplayFactory.CreateEffectSpec(Ability.costEffect);
                Owner.EffectsContainer.AddEffect(spec);
            }

            if (Ability.cooldownEffect)
            {
                var spec = GameplayFactory.CreateEffectSpec(Ability.cooldownEffect);
                Owner.EffectsContainer.AddEffect(spec);
            }

            Status = AbilityStatus.Activating;

            Owner.RegisterEvent(OnGameplayTriggerTagEvent);
        }

        /// <summary>
        /// 提交能力，暂时不知道干嘛的
        /// </summary>
        private void CommitAbility()
        {
        }

        /// <summary>
        /// 应用效果
        /// </summary>
        public void ApplyGameplayEffect(GameplayEffect effect)
        {
            Owner.EffectsContainer.AddEffect(GameplayFactory.CreateEffectSpec(effect));
        }

        /// <summary>
        /// 结束能力
        /// </summary>
        public void EndAbility()
        {
            Status = AbilityStatus.Idle;
            Cleanup();
        }

        /// <summary>
        /// 清理环境
        /// </summary>
        private void Cleanup()
        {
            Owner.UnregisterEvent(OnGameplayTriggerTagEvent);
        }

        public void OnUpdate(float dt)
        {
            TryBreak();
            Graph.UpdateBehaviour();
        }

        private void TryBreak()
        {
            if (Status != AbilityStatus.Activating)
            {
                return;
            }

            if (Ability.sourceBreakTags.Length > 0 && Owner.TagContainer.HasAny(Ability.sourceBreakTags))
            {
                Graph.SendEvent("BreakAbility", null, Owner);
            }
        }
    }
}